import webapp2
import json
import collections
from dal import *


class AdminQueues(webapp2.RequestHandler):   
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/<admin_id>/queues
    :action: gets the list of queues of the admin
    :return: the list of queues of the admin, 200 (OK)
             404 (Not Found) for invalid parameter or an error has occurred
    '''
    def get(self, admin_id):    
        try:
            queues = get_all_queues_from_admin_by_id(admin_id)
            if queues is None:
                self.abort(404)
            else:
                self.response.write(json.dumps(queues))
        except:
            self.abort(404)  
    
    '''
    :HTTP verb: POST
    :url: http://cyberqueue.appspot.com/api/<admin_id>/queues
    :params: queue name, queue_id, queue_type (Optional), queue_img (Optional) in JSON format
    :action: creates a queue for admin_id
    :return: 0 if the queue was successfully created, 201 (Created)
            -1 if the queue exists, 200 (OK)
            404 (Not Found) for invalid parameters or an error has occurred
    '''
    def post(self, admin_id):     
        try:
            values = json.loads(self.request.body)
            queue_name = values['queue_name']
            queue_id = values['queue_id']
        
            if "queue_type" in values:
                # the optional parameter queue_type was added
                queue_type = int(values['queue_type'])
            else:
                queue_type = 0
          
            if "queue_img" in values:
                # the optional parameter queue_img was added  
                queue_img = values['queue_img']
                queue_img = str(queue_img)
            else:
                queue_img = None
                   
            result = create_queue_by_id(admin_id, queue_name, queue_id, queue_type, queue_img)

            if result is None:
                self.abort(404)       
            else: 
                if result == 0:
                    self.response.set_status(201)   
                if result == -1:
                    # the queue already exists
                    self.response.set_status(200)   
                self.response.write(result)
        except:
            self.abort(404)


class Queue(webapp2.RequestHandler):  
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>
    :action: gets list of users keys in queue ID
    :return: List of users keys in queue_id, 200 (OK)
             404 (Not Found) for invalid parameter or an error has occurred
    '''  
    def get(self, queue_id):
        try:
            queue_list = get_all_users_in_queue(queue_id)
            if queue_list is None:
                self.abort(404)
            else:
                '''
                items = []
                for item in queue_list:
                    items.append(str(item.id()))
                '''
                self.response.write(queue_list)
        except:
            self.abort(404)
         
    '''
    :HTTP verb: POST
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>
    :params: new user details in JSON format: name, phone (Optional)
    :action: adds user to queue_id
    :return: user ID of the newly added user, 201 (Created)
             404 (Not Found) for invalid parameters or an error has occurred
    '''    
    def post(self, queue_id):
        try:
            values = json.loads(self.request.body)   
            if "phone" in values:
                values["phone"] = str(values["phone"])
            else:
                values["phone"] = "x"
        
            res = join_queue(values, queue_id) 
            if res is None:
                self.abort(404)
            else:              
                self.response.set_status(201)
                self.response.write(res)
        except:
            self.abort(404)
        
   
    '''
    :HTTP verb: DELETE
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>
    :action: deletes the queue
    :return: 204 (No Content)
             404 (Not Found) for invalid parameter or an error has occurred
    '''  
    def delete(self, queue_id):
        try:
            delete_queue(queue_id)
            self.response.set_status(204)
            return
        except:
            self.abort(404)


class QueueInfo(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/queue-info
    :action: gets the queue information - queue name, size and type
    :return: queueName, queueSize and queueType in JSON format, 200 (OK)
             if queue_id doesn't exist: queueName is an empty string
                                        queueSize = -1
                                        queueType = -1
             404 (Not Found) if an error has occurred
    '''
    def get(self, queue_id):
        try:
            queue_name = get_queue_name(queue_id)
            queue_size = get_queue_size(queue_id)
            queue_type = get_queue_type(queue_id)
            if ((queue_name is None) or (queue_size is None) or (queue_type is None)):
                self.abort(404)
            else:
                values = collections.OrderedDict([("queueName", queue_name), ("queueSize", queue_size), ("queueType", queue_type)])
                self.response.write(json.dumps(values))
        except:
            self.abort(404)
 
 
class QueueStatus(webapp2.RequestHandler):       
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/queue-status
    :action: gets the queue status
    :return: returns the queue status, 200 (OK)
             empty string if the queue doesn't exist, 200 (OK)
             404 (Not Found) if an error has occurred
    '''      
    def get(self, queue_id):
        try:
            status = get_queue_status(queue_id)
            if status is None:
                self.abort(404)
            else:
                self.response.write(status)
        except:
            self.abort(404)

    '''
    :HTTP verb: PUT
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/queue-status
    :params: status=1 for stopping the queue, status=0 for resuming the queue
    :action: updates the queue status, 200 (OK)
    :return: 200 (OK), 404 (Not Found) for invalid parameter or an error has occurred
    '''  
    def put(self, queue_id):
        try:
            status = int(self.request.POST.get('status'))
            if status == 1:
                stop_queue(queue_id)
                self.response.set_status(200)
                return
            if status == 0:
                resume_queue(queue_id)
                self.response.set_status(200)
                return
        except:
            self.abort(404)
            

class QueueImage(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/queue-image
    :action: gets the image of the queue
    :return: the image of the queue, 200 (OK)
             404 (Not Found) for invalid parameter or an error has occurred
    ''' 
    def get(self, queue_id):
        try:
            image = get_queue_image(queue_id)
            if image == None:
                self.abort(404)
            else:
                self.response.write(image)   
        except:
            self.abort(404)
    
    '''
    :HTTP verb: PUT
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/queue-image
    :params: queue_image
    :action: adds an image to the queue
    :return: 200 (OK), 404 (Not Found) for invalid parameter or an error has occurred
    '''
    def put(self, queue_id):
        try:
            queue_image = self.request.POST.get('queue_image')
            set_queue_image(queue_id, queue_image)
            self.response.set_status(200)
            return
        except:
            self.abort(404)
    
    '''
    :HTTP verb: DELETE
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/queue-image
    :action: deletes the image to the queue
    :return: 204 (No Content), 404 (Not Found) for invalid parameter or an error has occurred
    '''
    def delete(self, queue_id):
        try:
            del_queue_image(queue_id)
            self.response.set_status(204)
            return
        except:
            self.abort(404)
       

class QueueAdvance(webapp2.RequestHandler):  
    '''
    :HTTP verb: POST
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/queue-advance
    :params: ext (Optional)
    :action: advances the queue, and gets the first user in the new queue
    :return: the first user in the updated queue, 200 (OK)
             404 (Not Found) for invalid parameter or an error has occurred
    '''
    def post(self, queue_id):
        try:
            ext = str(self.request.POST.get('ext'))
            if not ext:
                next_user = advance_queue(queue_id)
            else:
                next_user = advance_queue(queue_id, ext)
            if next_user is None:
                self.abort(404)
            else:
                self.response.write(str(next_user))
        except:
            self.abort(404)
  

class CurrentUsers(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/users/in-service-users
    :params: user_id (Optional)
    :action: gets the users in the queue that are being served, and their extension numbers
             in JSON format
    :return: the users in the queue that are being served, and their extension numbers, 200 (OK)
             404 (Not Found) for invalid parameter or an error has occurred
    '''
    def get(self, queue_id):
        try:
            user_id = str(self.request.get("user_id"))
            
            if not user_id:
                res = get_inservice_users(queue_id)
            else:
                res = get_inservice_users(queue_id, user_id) 
                
            if res is None:
                self.abort(404) 
            else:
                self.response.write(json.dumps(res))
        except:
            self.abort(404)
    

class UsersCount(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/users?amount=<amount>
    :params: amount
    :action: gets the users in the queue, according to the given amount
    :return: the <amount> users in the queue. 200 (OK)
             404 (Not Found) for invalid parameters or an error has occurred
    '''
    def get(self, queue_id):
        try:
            amount = int(self.request.get("amount"))
            res = get_next_users(queue_id, amount)
            if res is None:
                self.abort(404)
            else:
                self.response.write(json.dumps(res))
        except:
            self.abort(404)
        

class User(webapp2.RequestHandler):  
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/users/<user_id>
    :action: gets user position in the queue
    :return: user position in the queue, 200 (OK)
             404 (Not Found) for invalid parameters or an error has occurred
    '''  
    
    def get(self, user_id, queue_id):
        try:
            position = get_user_pos_in_queue(user_id, queue_id)
            
            if position is None:
                self.abort(404)
            else:
                self.response.write(position)
        except:
            self.abort(404)
      
     
    '''
    :HTTP verb: DELETE
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/users/<user_id>
    :action: deletes user from the queue
    :return: 204 (No Content), 404 (Not Found) for invalid parameters or an error has occurred
    '''  
    def delete(self, queue_id, user_id):
        try:
            leave_queue(user_id, queue_id)
            self.response.set_status(204)
        except:
            self.abort(404)
 
 
class Users(webapp2.RequestHandler):
    '''
    :HTTP verb: POST
    :url: http://cyberqueue.appspot.com/api/users
    :params: details in JSON format
    :action: creates a users
    :return: 201 (Created)
             404 (Not Found) for invalid parameters or an error has occurred
    '''
    def post(self):
        try:
            values = json.loads(self.request.body)   
            if "phone" in values:
                values["phone"] = str(values["phone"])
            else:
                values["phone"] = "x"
        
            res = create_user(values) 
            if res is None:
                self.abort(404)
            else:              
                self.response.set_status(201)
                self.response.write(res)
        except:
            self.abort(404)
        

class UserDetails(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/users/<user_id>
    :action: gets user details: name, phone
    :returns: user details in JSON format, 200 (OK)
              404 (Not Found) for invalid parameter or an error has occurred
    '''  
    def get(self, user_id):     
        try:
            details = get_user_details(user_id) 
            if details is None:
                self.abort(404)
            else:     
                res = json.dumps(details)    
                self.response.write(res)
        except:
            self.abort(404)
 
     
class UserPositions(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/users/<user_id>/user-positions
    :action: gets user positions
    :returns: user positions, 200 (OK)
              404 (Not Found) for invalid parameters or an error has occurred
    '''  
    def get(self, user_id):
        try:
            positions = get_user_positions(user_id)
            if positions is None:
                self.abort(404)
            else:
                self.response.write(positions)
        except:
            self.abort(404)
 
 
class Position(webapp2.RequestHandler): 
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/position/<position>
    :action: gets position information: Position number, position status, queue id by position
    :return: positionNumber, positionStatus, queueId in JSON format, 200 (OK)
             404 (Not Found) for invalid parameters or an error has occurred
    '''  
    def get(self, position):
        try:
            position_number = get_pos_number(position)
            position_status = get_position_status(position)
            queue_id = get_queue_by_position(position)
            if ((position_number is None) or (position_status is None) or (queue_id is None)):
                self.abort(404)
            else:
                values = collections.OrderedDict([("positionNumber", position_number), 
                                                  ("positionStatus", position_status), 
                                                  ("queueId", queue_id)])
                self.response.write(json.dumps(values))
        except:
            self.abort(404)
 
        
class PositionStatus(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/position/<position>/status
    :action: gets position status
    :returns: position status, 200 (OK)
              404 (Not Found) for invalid parameters or an error has occurred
    '''  
    def get(self, user_id):
        try:
            status = get_position_status(user_id)
            if status is None:
                self.abort(404)
            else:
                self.response.write(status)
        except:
            self.abort(404)

      

class ValidUserCheck(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/user-check?user_id=<user_id>
    :params: user_id 
    :action: checks if a user is valid
    :returns: true if user_id is valid, false otherwise. 200 (OK)
              404 (Not Found) if an error has occurred
    '''  
    def get(self):
        try:
            user_id = str(self.request.get("user_id"))  
            user_check = is_valid_user(user_id)
            if user_check is None:
                self.abort(404)
            else:
                self.response.write(user_check)
        except:
            self.abort(404)
            

class ValidQueueCheck(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/queue-check?queue_id=<queue_id>
    :params: queue_id 
    :action: checks if a queue is valid
    :returns: true if queue_id is valid, false otherwise. 200 (OK)
              404 (Not Found) if an error has occurred
    '''  
    def get(self):
        try:
            queue_id = str(self.request.get("queue_id"))  
            queue_check = is_valid_queue(queue_id)
            if queue_check is None:
                self.abort(404)
            else:
                self.response.write(queue_check)
        except:
            self.abort(404)
        
        
class QueueStatistics(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/statistics
    :action: gets queue statistics
    :returns: returns queue statistics, 200 (OK)
              404 (Not Found) if an error has occurred
    '''  
    def get(self, queue_id):
        try:
            stats = get_queue_statistics(queue_id)
            if stats is None:
                self.abort(404)
            else:
                last_avg = stats[0]
                total_avg = stats[1]
                min_delta = stats[2]
                max_delta = stats[3]
                
                values = collections.OrderedDict([("last_avg", last_avg), ("total_avg", total_avg), 
                                                  ("min_delta", min_delta), ("max_delta", max_delta)])
                
                self.response.write(json.dumps(values))
        except:
            self.abort(404)
        

class LastServiceDelta(webapp2.RequestHandler):
    '''
    :HTTP verb: GET
    :url: http://cyberqueue.appspot.com/api/queue/<queue_id>/last-service-delta
    :action: gets last service delta
    :returns: returns last service delta, 200 (OK)
              404 (Not Found) if an error has occurred
    '''  
    def get(self, queue_id):
        try:
            res = get_last_service_delta(queue_id)
            if res is None:
                self.abort(404)
            else:
                self.response.write(res)
        except:
            self.abort(404)
        
 
class MainAPI(webapp2.RequestHandler):

    def get(self):
        self.response.write("<html><body><h1>EasyQueue API</h1></body></html>")  

             
app = webapp2.WSGIApplication([webapp2.Route('/api/<admin_id>/queues',
                                             handler = AdminQueues),
                               webapp2.Route('/api/queue/<queue_id>',
                                             handler = Queue),
                               webapp2.Route('/api/queue/<queue_id>/queue-info',
                                             handler = QueueInfo),
                               webapp2.Route('/api/queue/<queue_id>/queue-status',
                                             handler = QueueStatus),
                               webapp2.Route('/api/queue/<queue_id>/queue-image',
                                             handler = QueueImage),
                               webapp2.Route('/api/queue/<queue_id>/queue-advance',
                                             handler = QueueAdvance),
                               webapp2.Route('/api/queue/<queue_id>/users/in-service-users',
                                             handler = CurrentUsers),
                               webapp2.Route('/api/queue/<queue_id>/users',
                                             handler = UsersCount),
                               webapp2.Route('/api/queue/<queue_id>/users/<user_id>',
                                             handler = User),
                               webapp2.Route('/api/position/<position>',
                                             handler = Position),
                               webapp2.Router('/api/position/<position>/status', handler = PositionStatus),
                               webapp2.Route('/api/api/users',
                                             handler = Users),
                               webapp2.Route('/api/users/<user_id>/user-positions',
                                             handler = UserPositions),
                               webapp2.Route('/api/users/<user_id>',
                                             handler = UserDetails),
                               webapp2.Route('/api/<admin_id>/queues',
                                             handler = AdminQueues),
                               webapp2.Route('/api/user-check',
                                             handler = ValidUserCheck),
                               webapp2.Route('/api/queue-check',
                                             handler = ValidQueueCheck),
                               webapp2.Route('/api/queue/<queue_id>/statistics',
                                             handler = QueueStatistics),
                               webapp2.Route('/api/queue/<queue_id>/last-service-delta',
                                             handler = LastServiceDelta),
                               webapp2.Route('/api',
                                             handler = MainAPI)], debug=True)
